<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>拼音消消乐·发音计时版</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<style>
html,body{margin:0;padding:0;height:100%;background:#fff5e3;font-family:Arial,Helvetica,sans-serif;display:flex;justify-content:center;align-items:center}
#gameBox{width:90vw;max-width:400px;background:#fff7d0;border-radius:12px;box-shadow:0 8px 20px rgba(0,0,0,.15);padding:12px;box-sizing:border-box}
#bar{display:flex;justify-content:space-between;font-size:18px;margin-bottom:8px;color:#5d4037;display:none}
#board{display:grid;grid-template-columns:repeat(4,1fr);gap:8px}
.card{background:#ffe082;border-radius:10px;font-size:32px;display:flex;flex-direction:column;align-items:center;justify-content:center;height:22vw;max-height:90px;cursor:pointer;box-shadow:0 4px 6px rgba(0,0,0,.1);transition:transform .2s;user-select:none;position:relative}
.card.touched{transform:scale(.95)}
.card.hide{background:#fff7d0;color:transparent;pointer-events:none;box-shadow:inset 0 0 8px rgba(0,0,0,.1)}
.speaker{position:absolute;bottom:2px;right:4px;font-size:16px;display:none}
.card.matched .speaker{display:block}
#msg{text-align:center;font-size:20px;margin-top:8px;color:#5d4037}
#celebrate{position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;display:none;justify-content:center;align-items:center;font-size:60px;color:#ffc107;animation:pop .6s}
@keyframes pop{0%{transform:scale(0)}80%{transform:scale(1.2)}100%{transform:scale(1)}}
#rankList{font-size:14px;margin-top:8px;max-height:120px;overflow:auto}
#rankList div{display:flex;justify-content:space-between;padding:2px 6px}
.thisTime{font-weight:bold;color:#ff006e;background:#ffecee}

/* ===== 动态开始按钮 ===== */
#startBtn{width:100%;padding:14px 0;font-size:24px;background:#ff9800;color:#fff;border:none;border-radius:8px;cursor:pointer;animation:breath 1.5s ease-in-out infinite,pulse 2s infinite}
@keyframes breath{0%,100%{box-shadow:0 0 0 0 rgba(255,152,0,.7)}50%{box-shadow:0 0 0 12px rgba(255,152,0,0)}}
@keyframes pulse{0%{transform:scale(1)}50%{transform:scale(1.05)}100%{transform:scale(1)}}
#startBtn:active{background:#f57c00}
</style>
</head>
<body>
<div id="gameBox">
  <button id="startBtn">开始游戏</button>
  <div id="bar">
    <div>得分：<span id="s">0</span></div>
    <div id="timer">0.0 秒</div>
  </div>
  <div id="board"></div>
  <div id="msg"></div>
  <div id="rankList"></div>
</div>
<div id="celebrate">🎉 通关啦！</div>

<script>
/* ===== 配置 ===== */
const pinyins = [
  {py:'ā',img:'🍎'}, {py:'ō',img:'🐔'}, {py:'ē',img:'🦆'},
  {py:'ī',img:'🐝'}, {py:'ū',img:'🐰'}, {py:'ǖ',img:'🐟'},
  {py:'ai',img:'🐘'}, {py:'ei',img:'🐸'}
];
const boardSize = 16;
const pairCount = 8;
let cards = [], firstSel = null, lock = false, score = 0;
let t0 = 0, timerId = null, thisTime = null;

/* ===== 声音播放 ===== */
// 统一路径：音频文件与 html 放在同一文件夹即可
function speak(py){
  const audio = new Audio(`voices/${py}.mp3`);
  audio.play().catch(()=>playTone(600,200)); // 容错
}

/* ===== 简单提示音 ===== */
function playTone(f,d){
  try{
    const a=new (window.AudioContext||window.webkitAudioContext)();
    const o=a.createOscillator(), g=a.createGain();
    o.type='sine'; o.frequency.value=f;
    o.connect(g); g.connect(a.destination);
    g.gain.setValueAtTime(.15,a.currentTime);
    g.gain.exponentialRampToValueAtTime(.001,a.currentTime+d/1000);
    o.start(); o.stop(a.currentTime+d/1000);
  }catch(e){}
}

/* ===== 打乱 ===== */
function shuffle(a){
  for(let i=a.length-1;i>0;i--){
    const j=Math.floor(Math.random()*(i+1)); [a[i],a[j]]=[a[j],a[i]];
  }
  return a;
}

/* ===== 计时器 ===== */
function startTimer(){
  t0 = performance.now();
  clearInterval(timerId);
  timerId = setInterval(()=>{
    const sec = ((performance.now()-t0)/1000).toFixed(1);
    document.getElementById('timer').textContent = sec + ' 秒';
  },100);
}
function stopTimer(){
  clearInterval(timerId);
  return ((performance.now()-t0)/1000).toFixed(1);
}

/* ===== 排名 ===== */
function getRank(){
  return JSON.parse(localStorage.getItem('pinyinRank')||'[]');
}
function saveRank(time){
  const r = getRank();
  r.push({time:parseFloat(time),date:new Date().toLocaleString('zh-CN')});
  r.sort((a,b)=>a.time-b.time);
  if(r.length>10) r.length=10;
  localStorage.setItem('pinyinRank',JSON.stringify(r));
  return r;
}
function showRank(){
  const r = getRank();
  const box = document.getElementById('rankList');
  box.innerHTML = r.length ? '<b>🏆 排行榜</b>' : '';
  r.forEach((o,i)=>{
    const d=document.createElement('div');
    const isThis = (thisTime !== null && parseFloat(o.time) === parseFloat(thisTime));
    d.innerHTML=`<span>${i+1}. ${o.time} 秒</span><span>${o.date}</span>`;
    if(isThis) d.className = 'thisTime';
    box.appendChild(d);
  });
}

/* ===== 发牌 ===== */
function deal(){
  const board = document.getElementById('board');
  board.innerHTML = '';
  cards = []; score = 0; firstSel = null; lock = false; thisTime = null;
  document.getElementById('s').textContent = score;
  document.getElementById('msg').textContent = '';
  const pool = shuffle([...pinyins]).slice(0,pairCount);
  const list = shuffle([...pool,...pool]);
  list.forEach((item,idx)=>{
    const div = document.createElement('div');
    div.className = 'card';
    div.dataset.idx = idx; div.dataset.py = item.py;
    div.innerHTML = `<span>${item.img}</span><small style="font-size:18px">${item.py}</small>
                     <span class="speaker">🔊</span>`;
    div.addEventListener('click',handleCard);
    board.appendChild(div); cards.push(div);
  });
  startTimer(); showRank();
}

/* ===== 卡片点击 ===== */
function handleCard(e){
  if(lock) return;
  const card = e.currentTarget;
  if(card.classList.contains('hide')) return;
  playTone(400,200);
  card.classList.add('touched');
  setTimeout(()=>card.classList.remove('touched'),200);
  if(!firstSel){
    firstSel = card; card.style.border='3px solid #ff6f00'; return;
  }
  if(card===firstSel) return;
  lock=true;
  if(card.dataset.py === firstSel.dataset.py){
    speak(card.dataset.py); // 读拼音
    playTone(600,300);
    card.classList.add('hide','matched');
    firstSel.classList.add('hide','matched');
    firstSel.style.border='';
    score++; document.getElementById('s').textContent=score;
    firstSel=null; lock=false;
    checkWin();
  }else{
    playTone(200,250);
    card.style.border='3px solid #d32f2f';
    setTimeout(()=>{
      card.style.border=''; firstSel.style.border=''; firstSel=null; lock=false;
    },600);
  }
}

/* ===== 检查通关 ===== */
function checkWin(){
  if(document.querySelectorAll('.card.hide').length===boardSize){
    thisTime = stopTimer();
    //playTone(800,400);
    new Audio('voices/success.mp3').play()
    setTimeout(()=>{
      document.getElementById('celebrate').style.display='flex';
      document.getElementById('msg').textContent=`太棒了！用时 ${thisTime} 秒`;
      saveRank(thisTime); showRank();
      setTimeout(()=>{
        document.getElementById('celebrate').style.display='none';
        document.getElementById('startBtn').style.display='block';
        document.getElementById('bar').style.display='none';
      },3000);
    },300);
  }
}

/* ===== 开始按钮 ===== */
document.getElementById('startBtn').addEventListener('click',function(){
  this.style.display='none';
  document.getElementById('bar').style.display='flex';
  deal();
});

/* ===== 首次加载 ===== */
showRank();
</script>
</body>
</html>